package algebra.op;

import index.DescriptionIndex;

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.util.LinkedList;
import java.util.List;

import kb.ABox;
import kb.DescriptionLogicsKB;
import kb.TBox;
import utils.Util;
import utils.exception.OrderingDescriptionException;
import utils.exception.ProjectionException;
import utils.io.KBAccess;
import algebra.OrderingDescription;
import algebra.ProjectionDescription;
import algebra.visitors.ProjectionQueryVisitorEvaluator;
import algebra.visitors.QueryVisitorEvaluator;
import entities.ConceptAssertion;
import entities.concept.AndConcept;
import entities.concept.Concept;
import entities.concept.DomainConceptEQ;
import entities.concept.DomainConceptLTEQ;
import entities.concept.ExistsConcept;
import entities.concept.PConcept;
import entities.role.Role;

public class Test {
	

	/**
	 * @param args
	 * @throws OrderingDescriptionException 
	 * @throws IOException 
	 * @throws ProjectionException 
	 */
	public static void main(String[] args) throws OrderingDescriptionException, IOException, ProjectionException {
		ABox ab = null;
		if (args.length == 0) {
			System.err.println("Usage: Evaluator <query-file> <tbox-file> <abox-file>");
			System.exit(-1);
		}
		
		//OrderingDescription.ENABLE_OPTIMIZATIONS = true;
		//ProjectionQueryVisitorEvaluator.ENABLE_OPTIMIZATIONS = true;
		String filename = "dpreview";
		TBox tb = KBAccess.getTBox(filename+".tbox", true);
		System.out.println("Loaded TBox");
		
//		Concept query = Util.parseConcept("(and (= (role year) 2008) (exists (role hasAuthors) (= (role hasAuthors) Jan_Hladik)))");
//		Concept data = Util.parseConcept("(and Publication (= (role title) Proof_Systems_for_Effectively_Propositional_Logic.) (= (role year) 2008) (and (exists (role hasAuthors) (= (role name) Juan_Antonio_Navarro_Prez)) (exists (role hasAuthors) (and (= (role name) Andrei_Voronkov) (University_of_Manchester_Researcher) (= (role country) United_Kingdom))) ) (exists (role inProceedings) (IJCAR)) )");
//		System.out.println(Util.subsumes(data, query, tb));
//		System.out.println(data);
//		if (true) return;
		
		BufferedReader in = new BufferedReader(new FileReader(args[0]));
		DescriptionIndex idx = null;
		String lastIndex = "";
		String line = null;
		long indexTime = 0;
		while ((line = in.readLine()) != null) {
			line = line.trim();
			if (line.equals("") || line.startsWith("#")) {
				continue;
			}
			String[] toks = line.split("\t");
			
			if (toks.length != 4) {
				System.err.println("WARNING: Malformed line in query file '" + line + "'");
				continue;
			}
			
			String qId = toks[0];
			String odString = toks[1];
			String pdString = toks[3];
			ProjectionDescription pd = null;
			if (!pdString.trim().equals("un")) {
				pd = new ProjectionDescription(pdString);
			}
			DescriptionLogicsKB kb = DescriptionLogicsKB.newKBInstance(tb, ab);
			OrderingDescription od = new OrderingDescription(odString, kb);
			Concept selection = Util.parseConcept(toks[2]);
			
			if (!lastIndex.equals(odString) || idx == null) {
				lastIndex = odString;
				System.out.println("Building index: " + odString);
				idx = new DescriptionIndex(od);
				//idx.load(new BufferedReader(new FileReader("test.dbox")));
				indexTime = System.currentTimeMillis();
				//idx.load(new BufferedReader(new FileReader(filename+".abox")));
				idx.load(filename+".abox");
				indexTime = System.currentTimeMillis() - indexTime;
				System.out.println("Index TIME: " + indexTime + "ms");
			}

			//OrderingDescription.cacheHits = 0;
			//OrderingDescription.structuralSubsumptions = 0;
			//ProjectionQueryVisitorEvaluator.structuralSubsumptions = 0;
			long time = System.currentTimeMillis();		
			//		List<Concept> res = Evaluator.evaluate(idx, new DomainConceptLTEQ<Role, String>(new Role("g"), "3"), pd);
			//		List<Concept> res = Evaluator.evaluate(idx, new AndConcept(new DomainConceptLTEQ<Role, String>(new Role("year"), "2002"), new DomainConceptLTEQ<String, Role>("2000", new Role("year"))), pd);
			//		List<Concept> res = Evaluator.evaluate(idx, new ExistsConcept(new Role("hasAuthors"), new PConcept("RWTH_Aachen_Researcher")), pd);
			//		List<Concept> res = Evaluator.evaluate(idx, new ExistsConcept(new Role("inProceedings"), new PConcept("Artificial_intelligence")), pd);
			//		List<Concept> res = Evaluator.evaluate(idx, new ExistsConcept(new Role("inProceedings"), new PConcept("Description_Logics")), pd);
			InformativeObjectQuery iq = new InformativeObjectQuery(pd, new CQuery(selection));
			QueryVisitorEvaluator eval = new QueryVisitorEvaluator(kb, od);	
			List<ConceptAssertion> res = iq.acceptVisitor(eval);
			time = System.currentTimeMillis() - time;
			
			System.out.println("RESULTS\n-------");
			System.out.println("Query: " + qId + " "+ selection);
			System.out.println(res);
			System.out.println(res.size() + " results");
			System.out.println(Util.getCounter() + " subsumptions");
			System.out.println(OrderingDescription.getCacheHits() + " cache hits");
			System.out.println(OrderingDescription.getStructuralSubsumptions() + " structural subsumptions for ordering");
			System.out.println(ProjectionQueryVisitorEvaluator.getStructuralSubsumptions() + " structural subsumptions for projection");
			System.out.println("TIME: " + time + "ms");
			System.out.println("-------\n");
		}

	}

//	public static List<ConceptAssertion> evaluate(DescriptionIndex idx, Concept query, String pd) throws ProjectionException, OrderingDescriptionException {
//		if (pd == null || pd.equals("")) {
//			return idx.search(query);
//		}
//		return Evaluator.evaluate(idx, query, new ProjectionDescription(pd));
//	}
//	public static List<ConceptAssertion> evaluate(DescriptionIndex idx, Concept query, ProjectionDescription pd) throws ProjectionException, OrderingDescriptionException {
//		if (pd == null) {
//			return idx.search(query);
//		}
//		List<ConceptAssertion> result = new LinkedList<ConceptAssertion>();
//
//		List<ConceptAssertion> search = idx.search(query);
//		for (ConceptAssertion ca : search) {
//			result.addAll(ProjectionQueryVisitorEvaluator.project(ca, pd, null, idx.getOd().getTBox()));
//		}
//		return result;
//	}
}
